<template>
  <view class="form">
    <slot />
  </view>
</template>

<script lang="ts">
import Schema from 'async-validator'
import { defineComponent, reactive, toRefs, provide, watch } from '@vue/composition-api'
import deepClone from '@/utils/deep-clone'

export default defineComponent({
  props: {
    model: {
      type: Object,
      default: () => ({}),
    },
    modelValue: {
      type: Object,
      default: () => ({}),
    },
    rules: {
      type: Object,
      default: () => ({}),
    },
    labelWidth: {
      type: [Number, String],
      default: 152,
    },
    errorType: {
      type: String,
      default: 'toast', // toast message
    },
  },
  setup(props) {
    const state = reactive({
      validator: null,
      showError: false,
      errorMessage: {},
      fields: [] as any[],
    })
    const validateItem = (prop, callback?: () => void) => {
      if (!state.showError) {
        return
      }
      // 获取此时正在输入的值
      // prop 是通过 props传入的，表示当前要验证的字段，此例中指的就是 username
      const value = props.model[prop]
      // 获取 username 的验证规则
      const rule = props.rules[prop]

      if (!rule) {
        if (callback) {
          callback()
        }

        return
      }
      // 描述对象
      const descriptor = { [prop]: rule }
      // 传入描述对象，创建验证实例
      const validator = new Schema(descriptor)
      // 校验
      validator.validate({ [prop]: value }, (errors) => {
        const field = state.fields.find((x) => x.prop === prop)
        if (errors) {
          state.errorMessage[prop] = errors[0].message

          if (props.errorType === 'message') {
            field.vm.setError(errors[0].message)
          }
        } else {
          delete state.errorMessage[prop]

          if (props.errorType === 'message') {
            field.vm.setError('')
          }
        }

        if (callback) {
          callback()
        }
      })
    }
    // const setProxyValidate = (model) => {
    //   const p = {
    //     set(target, key, value) {
    //       debugger
    //       target[key] = value
    //       validateItem(key)
    //       return true
    //     },
    //   }

    //   new Proxy(model, p)
    // }
    const validate = (callback) => {
      return new Promise((resolve) => {
        state.showError = true
        // let valid = true
        let count = 0
        if (props.errorType === 'message') {
          state.fields.forEach((x) => x.vm.setError(''))
        }
        state.errorMessage = {}
        state.fields.forEach((node) => {
          const prop = node.prop
          validateItem(prop, () => {
            if (++count === state.fields.length) {
              const valid = Object.keys(state.errorMessage).length === 0

              const errorList = state.fields.map((x) => state.errorMessage[x.prop]).filter((x) => x)
              if (props.errorType === 'toast') {
                if (errorList.length) {
                  uni.showToast({ icon: 'none', title: errorList[0] })
                }
              }

              callback && callback(valid)

              resolve(valid)
            }
          })
        })
      })
    }

    // setProxyValidate(props.model)

    provide('formItemParent', {
      state: state,
      rules: props.rules,
      labelWidth: props.labelWidth,
      validateItem,
      addFormItem(formItem) {
        state.fields.push(formItem)
      },
      removeFormItem(prop) {
        const index = state.fields.findIndex((x) => x.prop === prop)

        state.fields.splice(index, 1)
      },
    })

    let oldVal = deepClone(props.model)

    watch(
      () => props.model,
      (newVal) => {
        console.log('newVal', oldVal, newVal)
        // Object.keys()
      }
    )

    return {
      ...toRefs(state),
      validate,
    }
  },
})
</script>
<style lang="scss" scoped>
.form {
  // background-color: $--bg-content-c;
}
</style>
